package com.dimples.dd.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dimples.dd.common.pojo.PageResult;
import com.dimples.dd.common.util.file.FileUtils;
import com.dimples.dd.system.convert.FileConvert;
import com.dimples.dd.system.framework.file.core.client.FileClient;
import com.dimples.dd.system.framework.file.core.client.s3.FilePreSignedUrlBO;
import com.dimples.dd.system.framework.file.core.utils.FileTypeUtils;
import com.dimples.dd.system.mapper.SystemFileMapper;
import com.dimples.dd.system.model.entity.SystemFileDO;
import com.dimples.dd.system.model.form.FileCreateForm;
import com.dimples.dd.system.model.query.FilePageQuery;
import com.dimples.dd.system.model.vo.FilePageVO;
import com.dimples.dd.system.model.vo.FilePreSignedUrlRespVO;
import com.dimples.dd.system.service.SystemFileConfigService;
import com.dimples.dd.system.service.SystemFileService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import static com.dimples.dd.common.exception.BizExceptionUtil.exception;
import static com.dimples.dd.common.exception.ErrorCode.FILE_NOT_EXISTS;

@Service
@RequiredArgsConstructor
public class SystemFileServiceImpl extends ServiceImpl<SystemFileMapper, SystemFileDO> implements SystemFileService{

    private final SystemFileConfigService fileConfigService;
    private final FileConvert fileConvert;

    @Override
    @SneakyThrows
    public String createFile(String name, String path, byte[] content) {
        // 计算默认的 path 名
        String mineType = FileTypeUtils.getMineType(content, name);
        if (StrUtil.isEmpty(path)) {
            path = FileUtils.generatePath(content, name);
        }
        // 如果 name 为空，则使用 path 填充
        if (StrUtil.isEmpty(name)) {
            name = path;
        }

        // 上传到文件存储器
        FileClient client = this.fileConfigService.getMasterFileClient();
        Assert.notNull(client, "客户端(master) 不能为空");
        String url = client.upload(content, path, mineType);

        // 保存到数据库
        SystemFileDO file = new SystemFileDO();
        file.setConfigId(client.getId());
        file.setName(name);
        file.setPath(path);
        file.setUrl(url);
        file.setMineType(mineType);
        file.setType(CollUtil.getLast(StrUtil.split(name, StrUtil.DOT)));
        file.setSize(content.length);
        this.baseMapper.insert(file);
        return url;
    }

    @Override
    public Long createFile(FileCreateForm fileCreateForm) {
        SystemFileDO file = this.fileConvert.form2Entity(fileCreateForm);
        this.baseMapper.insert(file);
        return file.getId();
    }

    @Override
    public FilePreSignedUrlRespVO getFilePreSignedUrl(String path) throws Exception {
        FileClient fileClient = fileConfigService.getMasterFileClient();
        FilePreSignedUrlBO preSignedObjectUrl = fileClient.getPreSignedObjectUrl(path);
        FilePreSignedUrlRespVO filePreSignedUrlRespVO = this.fileConvert.bo2Vo(preSignedObjectUrl);
        filePreSignedUrlRespVO.setConfigId(fileClient.getId());
        return filePreSignedUrlRespVO;
    }

    @Override
    public void deleteFile(Long id) throws Exception {
        // 校验存在
        SystemFileDO file = validateFileExists(id);

        // 从文件存储器中删除
        FileClient client = fileConfigService.getFileClient(file.getConfigId());
        Assert.notNull(client, "客户端({}) 不能为空", file.getConfigId());
        client.delete(file.getPath());

        // 删除记录
        this.baseMapper.deleteById(id);
    }

    private SystemFileDO validateFileExists(Long id) {
        SystemFileDO fileDO = this.baseMapper.selectById(id);
        if (fileDO == null) {
            throw exception(FILE_NOT_EXISTS);
        }
        return fileDO;
    }

    @Override
    public byte[] getFileContent(Long configId, String path) throws Exception {
        FileClient client = fileConfigService.getFileClient(configId);
        Assert.notNull(client, "客户端({}) 不能为空", configId);
        return client.getContent(path);
    }

    @Override
    public PageResult<FilePageVO> selectFilePage(FilePageQuery pageQuery) {
        PageResult<SystemFileDO> filePage = this.baseMapper.selectPage(pageQuery);
        return this.fileConvert.entity2Page(filePage);
    }
}
